#include <optional>
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>



std::optional<std::string> user_full_name(const std::string& login)
{
    std::cout << "user_full_name" << std::endl;
    return "yibo";
}

std::optional<std::string> to_html(const std::string& text)
{
    std::cout << "to_html" << std::endl;
    return "<html>" + text +"</html>";
}

template <typename T1, typename F>
auto transform(const std::optional<T1> &opt, F f)
    -> decltype(std::make_optional(f(opt.value())))
    {
        if (opt) {
            std::cout << "transform" << std::endl;
            return std::make_optional(f(opt.value()));
        } else {
            return {};
        }
    }

template <typename T>
std::optional<T> join(const std::optional<std::optional<T>> &opt)
{
    if (opt) {
        std::cout << "join" << std::endl;
        return opt.value();
    } else {
        return {};
    }
}

int main(int argc, char *argv[])
{
    std::optional<std::string> login = "login";

    join(transform(
        join(transform(
            login,
            user_full_name
        )),to_html));
    return 0;
}

